<?php

/**
 * fastadmin常用工具链方法
 */

if (!function_exists('fail')) {
	/**
	 * 主动抛错
	 */
	function fail($message, $data = [], $code = 0) {
		$result = [
			'code' => $code,
			'data' => $data,
			'msg' => is_array($message) ? json_encode($message) : $message,
		];

		// 如果未设置类型则自动判断
		$type = 'json';
		$response = \think\Response::create($result, $type, 200)->header([
			// 请求耗时
			'exec-time' => intval(microtime(true) - $_SERVER['REQUEST_TIME_FLOAT'] * 1000) . 'ms',
		]);

		// throw new \app\common\exception\ApiResponseException($response, $message);
		throw new \think\exception\HttpResponseException($response);
	}
}

if (!function_exists('succ')) {
	/**
	 * 成功返回
	 */
	function succ($data = [], $message = '') {
		$result = [
			'code' => 1,
			'data' => $data,
			'msg' => $message,
		];
		// 如果未设置类型则自动判断
		$type = 'json';
		$response = \think\Response::create($result, $type, 200)->header([
			// 请求耗时
			'exec-time' => intval(microtime(true) - $_SERVER['REQUEST_TIME_FLOAT'] * 1000) . 'ms',
			// 'timing'    => round(msectime() - $_SERVER['REQUEST_TIME_FLOAT'] * 1000) . 'ms'
		]);
		throw new \think\exception\HttpResponseException($response);
	}
}

if (!function_exists('dd')) {
	/**
	 * Dump and Die (打印并死掉)
	 */
	function dd() {
		foreach (func_get_args() as $v) {
			echo '<yz-dd>';
			highlight_string("<?php\n" . var_export($v, true));
			echo '</yz-dd>';
		}
		echo <<<HTML
	<style>yz-dd{display:block;unicode-bidi:embed;font-family:monospace;background:#f1f1f1;padding:1em;margin-bottom:20px}</style>
	<script>!function(){for(var e=document.querySelectorAll("yz-dd"),r=0;r<e.length;r++){e[r].querySelector("code")&&(e[r].innerHTML=e[r].querySelector("code").innerHTML);for(var l=e[r].querySelectorAll("span:first-child, span > span:first-child"),n=0;n<l.length;n++)"<?php"==l[n].innerText.replace(/\\n$/,"")&&l[n].remove();var o=e[r].querySelectorAll("br:first-of-type");for(n=0;n<o.length;n++){var t=o[n].previousSibling;t&&"<?php"==t.nodeValue&&(t.remove(),o[n].remove())}}}();</script>
HTML;
		die;
	}
}

if (!function_exists('call')) {
	/**
	 * 调用某个函数
	 *
	 * @param Closure|string $fn
	 * @param mixed ...$args
	 * @return mixed|null
	 */
	function call($fn = null, ...$args) {
		switch (true) {
		case $fn instanceof Closure:
		case is_string($fn) && function_exists($fn):
			return $fn(...$args);
		}

		return null;
	}
}

if (!function_exists('is_assoc')) {
	/**
	 * 是否为关联数组
	 * @param array $var
	 * @return bool
	 */
	function is_assoc($var) {
		return is_array($var) and $var !== array_values($var) and ($keys = array_keys($var)) !== array_filter($keys, 'is_int');
	}
}

if (!function_exists('array_depth')) {
	/**
	 * 取得数组深度
	 *
	 * @param $array
	 * @return int
	 */
	function array_depth($array) {
		$max_depth = 1;

		foreach ($array as $value) {
			if (is_array($value)) {
				$depth = array_depth($value) + 1;

				if ($depth > $max_depth) {
					$max_depth = $depth;
				}
			}
		}

		return $max_depth;
	}
}

if (!function_exists('splitbyname')) {
	/**
	 * 分裂数据中的 NAME
	 *
	 * @param int|string|array $data
	 * @param string $field
	 * @return array
	 */
	function splitbyname($data, $field = 'name') {
		if (is_int($data)) {
			$data = [$data];
		} else if (is_string($data)) {
			$data = explode(',', $data);
		} else if (is_array($data) && array_depth($data) > 1) {
			$data = array_column($data, $field);
		} else if (is_array($data) && is_assoc($data)) {
			$data = [$data[$field]];
		}

		return array_values(array_filter(array_unique($data), 'is_value'));
	}
}

if (!function_exists('splitbyid')) {
	/**
	 * 分裂数据中的 ID
	 *
	 * @param int|string|array $data
	 * @param string $field
	 * @return array
	 */
	function splitbyid($data, $field = 'id') {
		return array_values(array_filter(splitbyname($data, $field), 'is_numeric'));
	}
}

if (!function_exists('joinbyname')) {
	/**
	 * 联结数据中的 NAME
	 *
	 * @param int|string|array $data
	 * @param string $field
	 * @return string
	 */
	function joinbyname($data, $field = 'name') {
		return implode(',', DB::quote(splitbyname($data, $field)));
	}
}

if (!function_exists('joinbyid')) {
	/**
	 * 联结数据中的 ID
	 *
	 * @param int|string|array $data
	 * @param string $field
	 * @return string
	 */
	function joinbyid($data, $field = 'id') {
		return implode(',', splitbyid($data, $field));
	}
}

if (!function_exists('groupby')) {

	/**
	 * [数组元素按函数返回key=>value形式]
	 *
	 * @param    [type]                   $data [二维数组]
	 * @param    Closure                  $fn   [函数]
	 * @return   [type]                         [分组后的数据]
	 */
	function groupby($data, Closure $fn) {
		$ret = [];
		foreach ($data as $v) {
			@$ret[$fn($v)] = $v;
		}

		return $ret;
	}
}

if (!function_exists('groupsby')) {
	/**
	 * [数组元素按函数返回 key => 数组集合形式]
	 * @param    [type]                   $data
	 * @param    Closure                  $fn
	 *
	 * @return   [type]
	 */
	function groupsby($data, Closure $fn) {
		$ret = [];
		foreach ($data as $v) {
			@$ret[$fn($v)][] = $v;
		}

		return $ret;
	}
}

if (!function_exists('groupbyid')) {
	/**
	 * [数组元素按某个字段转key=>value]
	 *
	 * @param    [type]                   $data
	 * @param    string                   $field
	 * @return   [type]
	 */
	function groupbyid($data, $field = 'id') {
		$ret = [];
		foreach ($data as $v) {
			@$ret[$v[$field]] = $v;
		}

		return $ret;
	}
}

if (!function_exists('groupsbyid')) {
	function groupsbyid($data, $field = 'id') {
		$ret = [];
		foreach ($data as $v) {
			@$ret[$v[$field]][] = $v;
		}

		return $ret;
	}
}

if (!function_exists('groupbyprefix')) {
	function groupbyprefix(&$data) {
		if (!is_assoc($data)) {
			foreach ($data as &$v) {
				groupbyprefix($v);
			}
			return $data;
		}

		$result = [];
		foreach ($data as $k => $v) {
			if ($k[0] == '_') {
				list(, $group, $name) = explode('_', $k, 3);
				if (!$group || !$name) {
					continue;
				}

				$result[$group][$name] = $v;
				unset($data[$k]);
			}
		}

		return $data += $result;
	}
}

if (!function_exists('noncestr')) {
	/**
	 * [取随机字符串]
	 * @param    integer                  $kind  0 大小写+数字 1 小写 2 大写 3 数字
	 * @param    integer                  $length
	 * @return   [type]
	 */
	function noncestr($kind = 0, $length = 32) {
		$strings = 'abcdefghijklmnopqrstuvwxyz';
		$numbers = '0123456789';
		if ($kind == 0) {
			$strings = $strings . strtoupper($strings) . $numbers;
		} else if ($kind == 2) {
			$strings = strtoupper($strings);
		} else if ($kind == 3) {
			$strings = $numbers;
		}

		$noncestr = '';

		for ($i = 0; $i < $length; $i++) {
			$noncestr .= $strings[mt_rand(0, 35)];
		}
		return $noncestr;
	}
}

if (!function_exists('XMLToArray')) {
	/**
	 * [XML数据转换成数组]
	 * @param    [type]                   $xml
	 */
	function XMLToArray($xml) {
		libxml_disable_entity_loader(true);
		$obj = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
		return json_decode(json_encode($obj), true);
	}
}

if (!function_exists('arrayToXML')) {
	/**
	 * [数组转xml]
	 * @param    [type]                   $arr
	 * @return   [type]
	 */
	function arrayToXML($arr) {
		$code = '';
		foreach ($arr as $k => $v) {
			$code .= "<{$k}>{$v}</{$k}>";
		}

		return "<xml>{$code}</xml>";
	}
}

if (!function_exists('generate_order_id')) {
	/**
	 * 生成订单号
	 * @return string
	 */
	function generate_order_id() {
		$first = (time() + inc('GOI', 1)) . mt_rand(100, 999);
		$second = substr(sha1(uniqid() . $first . inc('OSH', 10)), -4);
		$third = substr(sha1(uniqid() . $second . inc('OSH', 100)), 0, 2);

		return strtoupper($first . $third . $second);
	}
}

if (!function_exists('exceptfields')) {
	/**
	 * 从数组中筛出特定字段
	 *
	 * @param array $data 源数组
	 * @param mixed $fields 筛选字段
	 * @param int $level 处理级别
	 * @return array
	 */
	function exceptfields(&$data, $fields, $level = 1) {
		if ($level > 2) {
			return $data;
		}
		if (!is_array($data)) {
			return $data;
		}
		if (is_string($fields)) {
			$fields = explode(',', $fields);
		}
		if (!is_array($fields)) {
			$fields = (array) $fields;
		}

		if (!is_assoc($data)) {
			foreach ($data as &$v) {
				exceptfields($v, $fields, $level + 1);
			}
			return $data;
		}

		foreach (array_keys($data) as $k) {
			foreach ($fields as $f) {
				if (fnmatch($f, $k)) {
					unset($data[$k]);
					break;
				}
			}
		}
		return $data;
	}
}

if (!function_exists('onlyfields')) {
	/**
	 * 从数组中筛选特定字段
	 *
	 * @param array $data 源数组
	 * @param mixed $fields 筛选字段
	 * @param int $level 处理级别
	 * @return array
	 */
	function onlyfields(&$data, $fields, $level = 1) {
		if ($level > 2) {
			return $data;
		}
		if ($fields == '*') {
			return $data;
		}
		if (!is_array($data)) {
			return $data;
		}
		if (is_string($fields)) {
			$fields = explode(',', $fields);
		}
		if (!is_array($fields)) {
			$fields = (array) $fields;
		}

		if (!is_assoc($data)) {
			foreach ($data as &$v) {
				onlyfields($v, $fields, $level + 1);
			}
			return $data;
		}

		foreach (array_keys($data) as $k) {
			$flag = false;
			foreach ($fields as $f) {
				if (fnmatch($f, $k)) {
					$flag = true;
					break;
				}
			}

			if (!$flag) {
				unset($data[$k]);
			}
		}
		return $data;
	}
}

if (!function_exists('transaction')) {
	/**
	 * 开启一个事务
	 *
	 * @param Closure $fn
	 * @return mixed
	 */
	function transaction($fn) {
		\think\Db::startTrans();
		try {
			$res = $fn();
			\think\Db::commit();
		} catch (ValidateException $e) {
			\think\Db::rollback();
			fail($e->getMessage());
		} catch (PDOException $e) {
			\think\Db::rollback();
			fail($e->getMessage());
		} catch (Exception $e) {
			\think\Db::rollback();
			fail($e->getMessage());
		}

		return $res;
	}
}

if (!function_exists('filterby')) {
	/**
	 * [针对 column 列的某个值过滤数组]
	 * @param    [type]                   $array
	 * @param    [type]                   $value
	 * @param    string                   $column
	 * @return   [type]
	 */
	function filterby($array, $value, $column = 'id') {
		return array_values(array_filter($array, function ($v) use ($column, $value) {
			return $v[$column] == $value;
		}));
	}
}

if (!function_exists('sortby')) {
	/**
	 * [针对二维数组某个字段做排序]
	 * @param    [type]                   &$array
	 * @param    [type]                   $orderby
	 * @return   [type]
	 */
	function sortby(&$array, $orderby) {
		$args = [];
		foreach (explode(',', $orderby) as $v) {
			list($name, $sort) = explode(' ', $v);

			$args[] = array_column($array, trim($name, '`'));
			$args[] = $sort == 'desc' ? SORT_DESC : SORT_ASC;
		}

		$args[] = &$array;
		array_multisort(...$args);
	}

}

if (!function_exists('sumby')) {
	function sumby($array, $column, $scale = 2) {
		$total = 0;
		foreach ($array as $item) {
			$total = bcadd($total, $item[$column], $scale);
		}

		return $total;
	}
}
if (!function_exists('countby')) {
	function countby($array, $value, $column = 'id') {
		return count(filterby($array, $value, $column));
	}
}